package cn.maihe.elg.operation.centers.follow.handler.service;

import cn.maihe.elg.operation.centers.follow.channel.dto.FollowBaseRespDTO;
import cn.maihe.elg.operation.centers.follow.channel.dto.GuarantorRevokeNoticeReqDTO;
import cn.maihe.elg.operation.centers.follow.channel.service.GuarantorRevokeNoticeChannelService;
import cn.maihe.elg.operation.centers.follow.enums.FollowRespCode;
import cn.maihe.elg.operation.centers.follow.exception.FollowException;
import cn.maihe.elg.operation.centers.follow.handler.FollowBaseResp;
import cn.maihe.elg.operation.centers.follow.handler.FollowCenterTradeService;
import cn.maihe.elg.operation.centers.follow.handler.dto.GuaranteeRevokeReqDTO;
import cn.maihe.elg.operation.centers.follow.handler.dto.bo.GuaranteeRevokeBO;
import cn.maihe.elg.operation.centers.supports.CenterTradeContext;
import cn.maihe.elg.operation.centers.supports.annotation.CenterTradeService;
import cn.maihe.elg.operation.model.dto.BaseResp;
import cn.maihe.elg.operation.model.enums.*;
import cn.maihe.elg.operation.repository.entity.*;
import cn.maihe.elg.operation.service.business.ProjectInfoService;
import cn.maihe.elg.operation.service.guarantee.GuaranteeService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.RevokeOrderInfoService;
import cn.maihe.elg.operation.supports.system.ElgResourceService;
import cn.maihe.elg.operation.utils.IdGenerate;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author caixh
 * @Date 2021/9/17.
 */
@CenterTradeService(
        provider = CenterProviderEnum.FOLLOW,
        centerNo = CenterNoEnum.SANMING,
        tradeType = TradeType.guarantee_revoke,
        reqClass = GuaranteeRevokeReqDTO.class,
        respClass = FollowBaseResp.class
)
@Slf4j
public class FollowGuaranteeRevokeService extends FollowCenterTradeService<GuaranteeRevokeReqDTO, BaseResp> {

    @Resource
    private ElgResourceService elgResourceService;
    @Resource
    private RevokeOrderInfoService revokeOrderInfoService;
    @Resource
    private GuaranteeService guaranteeService;
    @Resource
    private ProjectInfoService projectInfoService;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private GuarantorRevokeNoticeChannelService revokeNoticeChannelService;

    /**
     * 具体业务处理
     *
     * @param context
     */
    @Override
    public BaseResp processService(CenterTradeContext<GuaranteeRevokeReqDTO, BaseResp> context) {
        GuaranteeRevokeReqDTO reqBody = context.getReq();
        GuaranteeRevokeBO data = reqBody.getData();
        Assert.notNull(data, () -> "业务数据不能为空");

        GuaranteeDO guaranteeDO = guaranteeService.getGuarantee(context.getCenterId(), context.getOrgId(), data.getPolicyNo(), null);
        Assert.notNull(guaranteeDO, () -> "保函不存在");
        AcceptOrderInfoDO acceptOrderInfoDO = acceptOrderInfoService.getByAcceptOrderNo(guaranteeDO.getAcceptOrderNo());
        Assert.notNull(acceptOrderInfoDO, () -> "保函申请订单未找到");
        if (acceptOrderInfoDO.getStatus() != AcceptOrderStatus.HAS_OUT_GUARANTEE.getStatus()) {
            throw FollowException.of(FollowRespCode.FAILURE, "当前保函订单状态不能退保", null);
        }
        ProjectInfoDO projectInfo = projectInfoService.selectById(acceptOrderInfoDO.getProjectId());
        List<RevokeGuaranteeData> revokeGuaranteeDatas = revokeOrderInfoService.getRevokeGuaranteeData(projectInfo.getSectionCode(), data.getPolicyNo());
        if (!CollectionUtils.isEmpty(revokeGuaranteeDatas)) {
            List<Long> ids = revokeGuaranteeDatas.stream().filter(item -> item.getProcessStatus()==0||item.getProcessStatus()==1).map(RevokeGuaranteeData::getRevokeOrderId).collect(Collectors.toList());
//            RevokeOrderInfoCondition condition = RevokeOrderInfoCondition.builder()
//                    .andCenterIdEq(context.getCenterId()).andOrgIdEq(context.getOrgId())
//                    .andIdIn(ids.toArray()).andStatusNe(2);
//            boolean existsRevokeNo = revokeOrderInfoService.exists(condition.build());
            Assert.notEmpty(ids, () -> "已存在该撤销保函编号");
        }
        RevokeOrderInfo revokeOrderInfo = buildRevokeOrderInfo(context, projectInfo, data);
        List<RevokeGuaranteeData> revokeGuaranteeDataList = buildRevokeGuaranteeDataList(revokeOrderInfo, data, guaranteeDO);
//        acceptOrderInfoDO.setRevokeFlag(1);
        acceptOrderInfoDO.setStatus(AcceptOrderStatus.REVOKE_PROCESSING.getStatus());
        acceptOrderInfoDO.setRevokeFlag(RevokeFlagEnum.PROCESSING.getFlag());
        acceptOrderInfoDO.setRemark(data.getReason());
        revokeOrderInfoService.saveRevokeOrderInfo(acceptOrderInfoDO,revokeOrderInfo, revokeGuaranteeDataList);


//        asyncRevokeNotice(guaranteeDO);

        return null;
    }

    private void asyncRevokeNotice(GuaranteeDO guaranteeDO) {
        CompletableFuture.runAsync(() -> {

            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException("睡眠中断异常");
            }

            GuarantorRevokeNoticeReqDTO reqDTO = new GuarantorRevokeNoticeReqDTO();
            reqDTO.setPolicyNo(guaranteeDO.getGuaranteeNo());
            reqDTO.setStatus("7");
            reqDTO.setMsg("撤销完成");
            FollowBaseRespDTO respDTO = revokeNoticeChannelService.doRequest(reqDTO);
            Assert.notNull(respDTO, "响应报文不能为空");
            if (!"200".equals(respDTO.getCode())) {
                throw new RuntimeException("响应码非成功[" + respDTO.getCode() + ":" + respDTO.getMsg() + "]");
            }
            log.info("保函编号[{}] >> 撤销结果回调通知成功", guaranteeDO.getGuaranteeNo());
        }).whenCompleteAsync((r, e) -> {
            if (e != null) {
                log.error("保函编号[{}] >> 撤销结果回调通知异常：{}", guaranteeDO.getGuaranteeNo(), e.getMessage(), e);
            }
        });

    }

    private List<RevokeGuaranteeData> buildRevokeGuaranteeDataList(RevokeOrderInfo revokeOrderInfo, GuaranteeRevokeBO data, GuaranteeDO guaranteeDO) {
        List<RevokeGuaranteeData> reList = Lists.newArrayList();
        RevokeGuaranteeData.RevokeGuaranteeDataBuilder builder = RevokeGuaranteeData.builder();
        builder.id(IdGenerate.getId()).revokeOrderId(revokeOrderInfo.getId())
                .guaranteeNo(data.getPolicyNo()).serialNum(guaranteeDO.getSerialNum())
                .sectionCode(revokeOrderInfo.getSectionCode()).principal(data.getAccountName())
                .processStyle(0).processStatus(0);
        reList.add(builder.build());
        return reList;
    }

    private RevokeOrderInfo buildRevokeOrderInfo(CenterTradeContext<GuaranteeRevokeReqDTO, BaseResp> context, ProjectInfoDO projectInfo, GuaranteeRevokeBO data) {
        GuaranteeRevokeReqDTO req = context.getReq();
        //todo 文件下载 退款信息保存
        RevokeOrderInfo.RevokeOrderInfoBuilder builder = RevokeOrderInfo.builder();
        builder.centerId(projectInfo.getCenterId()).orgId(context.getOrgId())
                .revokeNo(data.getPolicyNo())
//                .revokeDeclareFile(revokeDeclareFile).revokeDeclareHash(req.getRevoke_guarantee_declare_file_hash())
                .projectCode(projectInfo.getProjectCode()).projectName(projectInfo.getProjectName())
                .sectionCode(projectInfo.getSectionCode()).sectionName(projectInfo.getSectionName())
                .tenderer(projectInfo.getTenderer()).note(req.getData().getReason())
                .bankName(data.getBankName())
                .accountName(data.getAccountName())
//                .openBankName(data.getOpenBankName())
                .bankCardNum(data.getBankCardNum())
                .backPremium(data.getBackPremium()==null?0L:(new BigDecimal(data.getBackPremium()).longValue()))

                .status(0).revokeGuaranteeData(JSON.toJSONString(req.getData().getFileList()));
        return builder.build();
    }


}
